Range #

当用户在听一首歌的时候,如果听到一半(网络下载了一半),网络断掉了,用户需要继续听的时候,文件服务器不支持断点的话,则用户需要重新下载这个文件。而Range支持的话,客户端应该记录了之前已经读取的文件范围,网络恢复之后,则向服务器发送读取剩余Range的请求,服务端只需要发送客户端请求的那部分内容,而不用整个文件发送回客户端,以此节省网络带宽。

获取部分内容的范围请求 #

为了实现中断恢复下载的需求,需要能下载指定下载的实体范围

curl -v --header "Range: bytes=2-100" http://www.zhufengpeixun.cn/skin/20142/img/logo.png

如何应用 #

1.1 服务端设置 #

// server
let http = require('http');
let url = require('url')
let path = require('path');
let fs = require('fs');
http.createServer(function(req,res){
    let p = path.join(__dirname,'./1.bytes.txt');
    let start = 0;
    fs.stat(p,function(err,stat){
        let start = 0
        let end  = stat.size - 1; // 文件的大小 
        let range = req.headers['range']; 
        if(range){
            res.setHeader('Accept-Range','bytes');
            res.statusCode = 206;
            let result = range.match(/bytes=(\d*)-(\d*)/);
            if(result){
                start = result[1]? parseInt(result[1]):start;
                end =result[2]? parseInt(result[2])-1:end
            }
        }
        return fs.createReadStream(p,{start,end}).pipe(res);
    })
}).listen(8080);

1.2 客户端设置 #

// client
let options = {
    hostname:'localhost',
    port:8080,
    path:'/',
    method:'GET'
}
let fs = require('fs');
let path = require('path');
let http = require('http');
let ws = fs.createWriteStream('./download.txt');
let start = 0; 
let pause = false
process.stdin.on('data',function(chunk){
    chunk = chunk.toString();
    if(chunk.startsWith('p')){
        pause = true;
    }else{
        pause = false;
        downLoad();
    }
})
function downLoad(){
    options.headers = {
        Range: `bytes=${start}-${start+10}`
    }
    start+=10;
    http.request(options,function(response){
        let buffers = []
        response.on('data',function(data){
            buffers.push(data);
        });
        response.on('end',function(){
            let b = Buffer.concat(buffers);
            ws.write(b);
            if(start<100&&pause === false){
                setTimeout(function(){
                    downLoad()
                },1000)
            }
        })
    })
}
downLoad();